<template>
	<div class="app-container">
		<div class="search-container">
			<el-form ref="queryFormRef" :inline="true" :model="queryParams">
				<el-form-item label="关键字" prop="keywords">
					<el-input
						v-model="queryParams.keywords"
						clearable
						placeholder="菜单名称"
						@keyup.enter="handleQuery"
					/>
				</el-form-item>
				<el-form-item>
					<el-button type="primary" @click="handleQuery"
					>
						<template #icon>
							<i-ep-search/>
						</template>
						搜索
					</el-button
					>
					<el-button @click="handleResetQuery">
						<template #icon>
							<i-ep-refresh/>
						</template>
						重置
					</el-button
					>
				</el-form-item>
			</el-form>
		</div>

		<el-card class="table-container" shadow="never">
			<template #header>
				<el-button
					v-hasPerm="['sys:menu:add']"
					type="success"
					@click="handleOpenDialog(0)"
				>
					<template #icon>
						<i-ep-plus/>
					</template>
					新增
				</el-button
				>
			</template>

			<el-table
				v-loading="loading"
				:data="menuTableData"
				:expand-row-keys="['1']"
				:tree-props="{
          children: 'children',
          hasChildren: 'hasChildren',
        }"
				highlight-current-row
				row-key="id"
				@row-click="handleRowClick"
			>
				<el-table-column label="菜单名称" min-width="200">
					<template #default="scope">
						<template
							v-if="scope.row.icon && scope.row.icon.startsWith('el-icon')"
						>
							<el-icon style="vertical-align: -0.15em">
								<component :is="scope.row.icon.replace('el-icon-', '')"/>
							</el-icon>
						</template>
						<template v-else-if="scope.row.icon">
							<svg-icon :icon-class="scope.row.icon"/>
						</template>
						<template v-else>
							<svg-icon icon-class="menu"/>
						</template>
						{{ scope.row.name }}
					</template>
				</el-table-column>

				<el-table-column align="center" label="类型" width="80">
					<template #default="scope">
						<el-tag
							v-if="scope.row.type === MenuTypeEnum.CATALOG"
							type="warning"
						>目录
						</el-tag
						>
						<el-tag v-if="scope.row.type === MenuTypeEnum.MENU" type="success"
						>菜单
						</el-tag
						>
						<el-tag v-if="scope.row.type === MenuTypeEnum.BUTTON" type="danger"
						>按钮
						</el-tag
						>
						<el-tag v-if="scope.row.type === MenuTypeEnum.EXTLINK" type="info"
						>外链
						</el-tag
						>
					</template>
				</el-table-column>

				<el-table-column
					align="left"
					label="路由名称"
					prop="routeName"
					width="150"
				/>

				<el-table-column
					align="left"
					label="路由路径"
					prop="routePath"
					width="150"
				/>

				<el-table-column
					align="left"
					label="组件路径"
					prop="component"
					width="250"
				/>

				<el-table-column
					align="center"
					label="权限标识"
					prop="perm"
					width="200"
				/>

				<el-table-column align="center" label="状态" width="80">
					<template #default="scope">
						<el-tag v-if="scope.row.visible === 1" type="success">显示</el-tag>
						<el-tag v-else type="info">隐藏</el-tag>
					</template>
				</el-table-column>

				<el-table-column align="center" label="排序" prop="sort" width="80"/>

				<el-table-column align="center" fixed="right" label="操作" width="220">
					<template #default="scope">
						<el-button
							v-if="scope.row.type == 'CATALOG' || scope.row.type == 'MENU'"
							v-hasPerm="['sys:menu:add']"
							link
							size="small"
							type="primary"
							@click.stop="handleOpenDialog(scope.row.id)"
						>
							<i-ep-plus/>
							新增
						</el-button>

						<el-button
							v-hasPerm="['sys:menu:edit']"
							link
							size="small"
							type="primary"
							@click.stop="handleOpenDialog(undefined, scope.row.id)"
						>
							<i-ep-edit/>
							编辑
						</el-button>
						<el-button
							v-hasPerm="['sys:menu:delete']"
							link
							size="small"
							type="danger"
							@click.stop="handleDelete(scope.row.id)"
						>
							<i-ep-delete/>
							删除
						</el-button>
					</template>
				</el-table-column>
			</el-table>
		</el-card>

		<el-drawer
			v-model="dialog.visible"
			:title="dialog.title"
			size="50%"
			@close="handleCloseDialog"
		>
			<el-form
				ref="menuFormRef"
				:model="formData"
				:rules="rules"
				label-width="100px"
			>
				<el-form-item label="父级菜单" prop="parentId">
					<el-tree-select
						v-model="formData.parentId"
						:data="menuOptions"
						:render-after-expand="false"
						check-strictly
						filterable
						placeholder="选择上级菜单"
					/>
				</el-form-item>

				<el-form-item label="菜单名称" prop="name">
					<el-input v-model="formData.name" placeholder="请输入菜单名称"/>
				</el-form-item>

				<el-form-item label="菜单类型" prop="type">
					<el-radio-group
						v-model="formData.type"
						@change="handleMenuTypeChange"
					>
						<el-radio value="CATALOG">目录</el-radio>
						<el-radio value="MENU">菜单</el-radio>
						<el-radio value="BUTTON">按钮</el-radio>
						<el-radio value="EXTLINK">外链</el-radio>
					</el-radio-group>
				</el-form-item>

				<el-form-item
					v-if="formData.type == 'EXTLINK'"
					label="外链地址"
					prop="path"
				>
					<el-input
						v-model="formData.routePath"
						placeholder="请输入外链完整路径"
					/>
				</el-form-item>

				<el-form-item
					v-if="formData.type == MenuTypeEnum.MENU"
					prop="routeName"
				>
					<template #label>
						<div>
							路由名称
							<el-tooltip effect="light" placement="bottom">
								<template #content>
									如果需要开启缓存，需保证页面 defineOptions 中的 name
									与此处一致，建议使用驼峰。
								</template>
								<i-ep-QuestionFilled class="inline-block"/>
							</el-tooltip>
						</div>
					</template>
					<el-input v-model="formData.routeName" placeholder="User"/>
				</el-form-item>

				<el-form-item
					v-if="
            formData.type == MenuTypeEnum.CATALOG ||
            formData.type == MenuTypeEnum.MENU
          "
					prop="routePath"
				>
					<template #label>
						<div>
							路由路径
							<el-tooltip effect="light" placement="bottom">
								<template #content>
									定义应用中不同页面对应的 URL 路径，目录需以 /
									开头，菜单项不用。例如：系统管理目录
									/system，系统管理下的用户管理菜单 user。
								</template>
								<i-ep-QuestionFilled class="inline-block"/>
							</el-tooltip>
						</div>
					</template>
					<el-input
						v-if="formData.type == MenuTypeEnum.CATALOG"
						v-model="formData.routePath"
						placeholder="system"
					/>
					<el-input v-else v-model="formData.routePath" placeholder="user"/>
				</el-form-item>

				<el-form-item
					v-if="formData.type == MenuTypeEnum.MENU"
					prop="component"
				>
					<template #label>
						<div>
							组件路径
							<el-tooltip effect="light" placement="bottom">
								<template #content>
									组件页面完整路径，相对于 src/views/，如
									system/user/index，缺省后缀 .vue
								</template>
								<i-ep-QuestionFilled class="inline-block"/>
							</el-tooltip>
						</div>
					</template>

					<el-input
						v-model="formData.component"
						placeholder="system/user/index"
						style="width: 95%"
					>
						<template v-if="formData.type == MenuTypeEnum.MENU" #prepend
						>src/views/
						</template
						>
						<template v-if="formData.type == MenuTypeEnum.MENU" #append
						>.vue
						</template
						>
					</el-input>
				</el-form-item>

				<el-form-item v-if="formData.type == MenuTypeEnum.MENU">
					<template #label>
						<div>
							路由参数
							<el-tooltip effect="light" placement="bottom">
								<template #content>
									组件页面使用 `useRoute().query.参数名` 获取路由参数值。
								</template>
								<i-ep-QuestionFilled class="inline-block"/>
							</el-tooltip>
						</div>
					</template>

					<div v-if="!formData.params || formData.params.length === 0">
						<el-button
							plain
							type="success"
							@click="formData.params = [{ key: '', value: '' }]"
						>添加路由参数
						</el-button
						>
					</div>

					<div v-else>
						<div v-for="(item, index) in formData.params" :key="index">
							<el-input
								v-model="item.key"
								class="w-[100px]"
								placeholder="参数名"
							/>

							<span class="mx-1">=</span>

							<el-input
								v-model="item.value"
								class="w-[100px]"
								placeholder="参数值"
							/>

							<el-icon
								v-if="
                  formData.params.indexOf(item) === formData.params.length - 1
                "
								class="ml-2 cursor-pointer color-[var(--el-color-success)]"
								style="vertical-align: -0.15em"
								@click="formData.params.push({ key: '', value: '' })"
							>
								<CirclePlusFilled/>
							</el-icon>
							<el-icon
								class="ml-2 cursor-pointer color-[var(--el-color-danger)]"
								style="vertical-align: -0.15em"
								@click="
                  formData.params.splice(formData.params.indexOf(item), 1)
                "
							>
								<DeleteFilled/>
							</el-icon>
						</div>
					</div>
				</el-form-item>

				<el-form-item
					v-if="formData.type !== MenuTypeEnum.BUTTON"
					label="显示状态"
					prop="visible"
				>
					<el-radio-group v-model="formData.visible">
						<el-radio :value="1">显示</el-radio>
						<el-radio :value="0">隐藏</el-radio>
					</el-radio-group>
				</el-form-item>

				<el-form-item
					v-if="
            formData.type === MenuTypeEnum.CATALOG ||
            formData.type === MenuTypeEnum.MENU
          "
				>
					<template #label>
						<div>
							始终显示
							<el-tooltip effect="light" placement="bottom">
								<template #content>
									选择“是”，即使目录或菜单下只有一个子节点，也会显示父节点。<br/>
									选择“否”，如果目录或菜单下只有一个子节点，则只显示该子节点，隐藏父节点。<br/>
									如果是叶子节点，请选择“否”。
								</template>
								<i-ep-QuestionFilled class="inline-block"/>
							</el-tooltip>
						</div>
					</template>

					<el-radio-group v-model="formData.alwaysShow">
						<el-radio :value="1">是</el-radio>
						<el-radio :value="0">否</el-radio>
					</el-radio-group>
				</el-form-item>

				<el-form-item
					v-if="formData.type === MenuTypeEnum.MENU"
					label="页面缓存"
				>
					<el-radio-group v-model="formData.keepAlive">
						<el-radio :value="1">开启</el-radio>
						<el-radio :value="0">关闭</el-radio>
					</el-radio-group>
				</el-form-item>

				<el-form-item label="排序" prop="sort">
					<el-input-number
						v-model="formData.sort"
						:min="0"
						controls-position="right"
						style="width: 100px"
					/>
				</el-form-item>

				<!-- 权限标识 -->
				<el-form-item
					v-if="formData.type == MenuTypeEnum.BUTTON"
					label="权限标识"
					prop="perm"
				>
					<el-input v-model="formData.perm" placeholder="sys:user:add"/>
				</el-form-item>

				<el-form-item
					v-if="formData.type !== MenuTypeEnum.BUTTON"
					label="图标"
					prop="icon"
				>
					<!-- 图标选择器 -->
					<icon-select v-model="formData.icon"/>
				</el-form-item>

				<el-form-item
					v-if="formData.type == MenuTypeEnum.CATALOG"
					label="跳转路由"
				>
					<el-input v-model="formData.redirect" placeholder="跳转路由"/>
				</el-form-item>
			</el-form>

			<template #footer>
				<div class="dialog-footer">
					<el-button type="primary" @click="submitForm">确 定</el-button>
					<el-button @click="handleCloseDialog">取 消</el-button>
				</div>
			</template>
		</el-drawer>
	</div>
</template>

<script lang="ts" setup>
defineOptions({
	name: "Menu",
	inheritAttrs: false,
});

import MenuAPI, {MenuQuery, MenuForm, MenuVO} from "@api/menu";
import {MenuTypeEnum} from "@themeDefault/enums/MenuTypeEnum";

const queryFormRef = ref(ElForm);
const menuFormRef = ref(ElForm);

const loading = ref(false);
const dialog = reactive({
	title: "新增菜单",
	visible: false,
});

// 查询参数
const queryParams = reactive<MenuQuery>({});
// 菜单表格数据
const menuTableData = ref<MenuVO[]>([]);
// 顶级菜单下拉选项
const menuOptions = ref<OptionType[]>([]);

// 初始菜单表单数据
const initialMenuFormData = ref<MenuForm>({
	id: undefined,
	parentId: 0,
	visible: 1,
	sort: 1,
	type: MenuTypeEnum.MENU, // 默认菜单
	alwaysShow: 0,
	keepAlive: 1,
	params: [],
});

// 菜单表单数据
const formData = ref({...initialMenuFormData.value});

// 表单验证规则
const rules = reactive({
	parentId: [{required: true, message: "请选择顶级菜单", trigger: "blur"}],
	name: [{required: true, message: "请输入菜单名称", trigger: "blur"}],
	type: [{required: true, message: "请选择菜单类型", trigger: "blur"}],
	routeName: [{required: true, message: "请输入路由名称", trigger: "blur"}],
	routePath: [{required: true, message: "请输入路由路径", trigger: "blur"}],
	component: [{required: true, message: "请输入组件路径", trigger: "blur"}],
	visible: [{required: true, message: "请输入路由路径", trigger: "blur"}],
});

// 选择表格的行菜单ID
const selectedMenuId = ref<number | undefined>();

// 查询
function handleQuery() {
	loading.value = true;
	MenuAPI.getList(queryParams)
		.then((data) => {
			menuTableData.value = data;
		})
		.finally(() => {
			loading.value = false;
		});
}

// 重置查询
function handleResetQuery() {
	queryFormRef.value.resetFields();
	handleQuery();
}

// 行点击事件
function handleRowClick(row: MenuVO) {
	// 记录表格选择的菜单ID，新增子菜单作为父菜单ID
	selectedMenuId.value = row.id;
}

/**
 * 打开表单弹窗
 *
 * @param parentId 父菜单ID
 * @param menuId 菜单ID
 */
function handleOpenDialog(parentId?: number, menuId?: number) {
	MenuAPI.getOptions()
		.then((data) => {
			menuOptions.value = [{value: 0, label: "顶级菜单", children: data}];
		})
		.then(() => {
			dialog.visible = true;
			if (menuId) {
				dialog.title = "编辑菜单";
				MenuAPI.getFormData(menuId).then((data) => {
					initialMenuFormData.value = {...data};
					formData.value = data;
				});
			} else {
				dialog.title = "新增菜单";
				formData.value.parentId = parentId;
			}
		});
}

// 菜单类型切换
function handleMenuTypeChange() {
	// 如果菜单类型改变
	if (formData.value.type !== initialMenuFormData.value.type) {
		if (formData.value.type === MenuTypeEnum.MENU) {
			// 目录切换到菜单时，清空组件路径
			if (initialMenuFormData.value.type === MenuTypeEnum.CATALOG) {
				formData.value.component = "";
			} else {
				// 其他情况，保留原有的组件路径
				formData.value.routePath = initialMenuFormData.value.routePath;
				formData.value.component = initialMenuFormData.value.component;
			}
		}
	}
}

/** 菜单保存提交 */
function submitForm() {
	menuFormRef.value.validate((isValid: boolean) => {
		if (isValid) {
			const menuId = formData.value.id;
			if (menuId) {
				MenuAPI.update(menuId, formData.value).then(() => {
					ElMessage.success("修改成功");
					handleCloseDialog();
					handleQuery();
				});
			} else {
				MenuAPI.add(formData.value).then(() => {
					ElMessage.success("新增成功");
					handleCloseDialog();
					handleQuery();
				});
			}
		}
	});
}

// 删除菜单
function handleDelete(menuId: number) {
	if (!menuId) {
		ElMessage.warning("请勾选删除项");
		return false;
	}

	ElMessageBox.confirm("确认删除已选中的数据项?", "警告", {
		confirmButtonText: "确定",
		cancelButtonText: "取消",
		type: "warning",
	}).then(
		() => {
			loading.value = true;
			MenuAPI.deleteById(menuId)
				.then(() => {
					ElMessage.success("删除成功");
					handleQuery();
				})
				.finally(() => {
					loading.value = false;
				});
		},
		() => {
			ElMessage.info("已取消删除");
		}
	);
}

// 关闭弹窗
function handleCloseDialog() {
	dialog.visible = false;
	menuFormRef.value.resetFields();
	menuFormRef.value.clearValidate();
	formData.value.id = undefined;
}

onMounted(() => {
	handleQuery();
});
</script>
